package com.alibaba.citrus.cr.mn.order.center.forecastorder.service.impl;

import com.alibaba.acm.shaded.com.google.common.collect.Lists;
import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.enums.GeneralStatusEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.InnerMessageEventEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.SalesOrderCloseEnum;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.lock.SaleRedisLock;
import com.alibaba.citrus.cr.common.util.ThreadPoolUtil;
import com.alibaba.citrus.cr.mn.order.center.common.constants.ForecastConstants;
import com.alibaba.citrus.cr.mn.order.center.common.constants.RedisLockConstants;
import com.alibaba.citrus.cr.mn.order.center.common.util.StopWatchUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BcLinkAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.function.check.CommonCheck;
import com.alibaba.citrus.cr.mn.order.center.facade.function.common.SendMsgService;
import com.alibaba.citrus.cr.mn.order.center.facade.function.convert.AnalysisForecastBizDTOTODOConvert;
import com.alibaba.citrus.cr.mn.order.center.facade.function.convert.ConfirmDTOInnerToOuterConvert;
import com.alibaba.citrus.cr.mn.order.center.facade.function.convert.ConfirmForecastBizDTOTODOConvert;
import com.alibaba.citrus.cr.mn.order.center.facade.kafka.KafkaUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.ForecastOrderLineQueryRepository;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.ForecastOrderLineWriteRepository;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.ForecastOrderQueryRepository;
import com.alibaba.citrus.cr.mn.order.center.facade.repository.ForecastOrderWriteRepository;
import com.alibaba.citrus.cr.mn.order.center.forecastorder.ability.ForecastOrderAbility;
import com.alibaba.citrus.cr.mn.order.center.forecastorder.ability.ForecastOrderBatchCreateAbility;
import com.alibaba.citrus.cr.mn.order.center.forecastorder.convert.ForecastOrderBOToResponseDTOConvertor;
import com.alibaba.citrus.cr.mn.order.center.forecastorder.entity.ForecastOrderEntity;
import com.alibaba.citrus.cr.mn.order.center.forecastorder.factory.ForecastOrderFactory;
import com.alibaba.citrus.cr.mn.order.center.forecastorder.service.ForecastOrderBizWriteService;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.crforecastsales.api.forecastorderwrite.service.ForecastOrderWriteService;
import com.epoch.app.crforecastsales.bo.ForecastOrderBO;
import com.epoch.app.crforecastsales.domian.forecastorder.dto.BatchUpdateStatusByIdsRequest;
import com.epoch.app.crforecastsales.domian.forecastorder.dto.QueryBySourceNoRequest;
import com.epoch.app.crforecastsales.domian.forecastorder.service.ForecastOrderService;
import com.epoch.app.crforecastsales.domian.forecastorderline.dto.BatchQueryByBizDoListResponse;
import com.epoch.app.crforecastsales.dto.request.BatchAnalysisOrdersRequest;
import com.epoch.app.crforecastsales.enums.ForecastStatusEnum;
import com.epoch.app.crforecastsales.model.dto.*;
import com.epoch.app.crforecastsales.sdo.ForecastOrderLineSDO;
import com.epoch.app.crforecastsales.sdo.ForecastOrderSDO;
import com.epoch.app.crplatformenhance.model.dto.ApiContext;
import com.epoch.app.crpricecenter.model.enums.ActivityTypeEnum;
import com.epoch.app.mnordercenter.contants.MnOrderCenterConstants;
import com.epoch.app.mnordercenter.model.dto.*;
import com.epoch.app.mnordercenter.model.enums.AsyncMessageEventEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.*;

@Service
@Primary
public class ForecastOrderBizWriteServiceImpl implements ForecastOrderBizWriteService {
    private static final Log log = Log.getLogger(ForecastOrderBizWriteServiceImpl.class);

    public static final String ACTION_TYPE_MODIFY = "MODIFY";
    public static final String ACTION_TYPE_MODIFY_COMPLETE = "MODIFY_COMPLETE";
    public static final String ACTION_TYPE_SUBMIT = "SUBMIT";

    @Autowired
    private ForecastOrderBatchCreateAbility forecastOrderBatchCreateAbility;
    @Autowired
    private ForecastOrderWriteRepository forecastOrderWriteRepository;
    @Autowired
    private ForecastOrderQueryRepository forecastOrderQueryRepository;
    @Autowired
    private ForecastOrderLineWriteRepository forecastOrderLineWriteRepository;
    @Autowired
    private ForecastOrderLineQueryRepository forecastOrderLineQueryRepository;
    @Autowired
    private ForecastOrderWriteService forecastOrderWriteService;
    @Resource
    private ForecastOrderService forecastOrderService;
    @Resource
    private CommonCheck commonCheck;
    @Resource
    private BcLinkAdapter bcLinkAdapter;
    @Resource
    private SendMsgService sendMsgService;

    @Override
    public List<CreateForecastResponseDTO> batchCreate(List<ForecastOrderBO> forecastOrderBOS, String taskId, String fromSys, String businessUnitCode) {
        List<CreateForecastResponseDTO> createResponseList = new ArrayList<>();
        try {
            if (CollectionUtils.isEmpty(forecastOrderBOS)) {
                throw new FunctionException("OC-01-001-01-15-001", "单据列表");
            }

            List<ForecastOrderBO> createForecastOrderBOS = new ArrayList<>();
            List<ForecastOrderEntity> forecastOrderEntities = ForecastOrderFactory.createBODraft(forecastOrderBOS);
            for (ForecastOrderEntity forecastOrderEntity : forecastOrderEntities) {
                ForecastOrderBO forecastOrderBO = forecastOrderEntity.getForecastOrderBO();

                String sourceLockKey = RedisLockConstants.FORECAST_ORDER_BIZ_PREFIX + forecastOrderBO.getSourceOrderNo();
                try (SaleRedisLock sourceLock = new SaleRedisLock(RedisLockConstants.CACHE_CODE, sourceLockKey, RedisLockConstants.TIMEOUT_MSECS, RedisLockConstants.EXPIRE_MSECS, RedisLockConstants.SLEEP_MILLIS)) {
                    if (!sourceLock.lock()) {
                        log.error("ForecastOrderBizDomainServiceImpl#batchCreate 分布式锁获取失败 sourceLockKey={}", sourceLockKey);
                        CreateForecastResponseDTO createForecastResponseDTO = forecastOrderEntity.buildLostLockCreateResponse(taskId);
                        createResponseList.add(createForecastResponseDTO);
                        continue;
                    }
                    ForecastOrderAbility forecastOrderAbility = forecastOrderEntity.getForecastOrderAbility();
                    // 来源单号幂等校验
                    Boolean idempotentProcess = forecastOrderAbility.idempotentProcess(taskId, forecastOrderBO, createResponseList);
                    if (!idempotentProcess) {
                        continue;
                    }
                    createForecastOrderBOS.add(forecastOrderBO);
                }
            }
            log.info("createForecastOrderBOS参数:{}",JSON.toJSONString(createForecastOrderBOS));
            //业务校验
            forecastOrderBatchCreateAbility.invalidMainData(createForecastOrderBOS, createResponseList, taskId);
            log.info("createForecastOrderBOS补全后参数:{}",JSON.toJSONString(createForecastOrderBOS));
            //批量保存
            batchSave(createForecastOrderBOS, createResponseList, taskId);
        } catch (Exception e) {
            log.error("批量创建预报订单异常", e);
        }

        CommonAsyncMessageResponse commonAsyncMessageResponse = buildCommonAsyncMessageResponse(AsyncMessageEventEnum.FORECAST_ORDER_CREATE, fromSys, businessUnitCode, createResponseList);
        //返回异步消息
        String messageKey = KafkaUtils.generateMessageKey(fromSys, "", businessUnitCode, commonAsyncMessageResponse.getEventCode());
        log.info("ForecastOrderBizDomainServiceImpl#batchCreate kafka key={} msg={}", messageKey, JSON.toJSONString(commonAsyncMessageResponse));
        SendResult<Integer, String> sendResult = KafkaUtils.send(MnOrderCenterConstants.MN_KAFKA_TOPIC(), messageKey, JSON.toJSONString(commonAsyncMessageResponse));

        // 预报单创建成功通知应用
        List<String> bizOrderNoList = createResponseList.stream().filter(CreateForecastResponseDTO::getSuccess).map(CreateForecastResponseDTO::getSalesOrderNo).collect(toList());
        sendMsgService.sendForecastOrderChangeMsg(bizOrderNoList, InnerMessageEventEnum.FORECAST_ORDER_CREATED);

        return createResponseList;
    }

    @Override
    public List<CreateForecastResponseDTO> batchCreateWithReturn(List<ForecastOrderBO> forecastOrderBOS, String taskId, String fromSys, String businessUnitCode) {
        List<CreateForecastResponseDTO> createResponseList = new ArrayList<>();
        try {
            if (CollectionUtils.isNotEmpty(forecastOrderBOS)) {
                List<ForecastOrderBO> createForecastOrderBOS = new ArrayList<>();
                List<ForecastOrderEntity> forecastOrderEntities = ForecastOrderFactory.createBODraftNotCoverFeature(forecastOrderBOS);
                for (ForecastOrderEntity forecastOrderEntity : forecastOrderEntities) {
                    ForecastOrderBO forecastOrderBO = forecastOrderEntity.getForecastOrderBO();

                    String sourceLockKey = RedisLockConstants.FORECAST_ORDER_BIZ_PREFIX + forecastOrderBO.getSourceOrderNo();
                    try (SaleRedisLock sourceLock = new SaleRedisLock(RedisLockConstants.CACHE_CODE, sourceLockKey, RedisLockConstants.TIMEOUT_MSECS, RedisLockConstants.EXPIRE_MSECS, RedisLockConstants.SLEEP_MILLIS)) {
                        if (!sourceLock.lock()) {
                            log.error("ForecastOrderBizDomainServiceImpl#batchCreateWithReturn 分布式锁获取失败 sourceLockKey={}", sourceLockKey);
                            CreateForecastResponseDTO createForecastResponseDTO = forecastOrderEntity.buildLostLockCreateResponse(taskId);
                            createResponseList.add(createForecastResponseDTO);
                            continue;
                        }
                        ForecastOrderAbility forecastOrderAbility = forecastOrderEntity.getForecastOrderAbility();
                        // 来源单号幂等校验
                        Boolean idempotentProcess = forecastOrderAbility.idempotentProcess(taskId, forecastOrderBO, createResponseList);
                        if (!idempotentProcess) {
                            continue;
                        }
                        createForecastOrderBOS.add(forecastOrderBO);
                    } catch (Exception e) {
                        log.error("ForecastOrderBizDomainServiceImpl#batchCreateWithReturn error", e);
                        throw e;
                    }
                }
                //业务校验
                forecastOrderBatchCreateAbility.invalidMainData(createForecastOrderBOS, createResponseList, taskId);

                //批量保存
                batchSaveNotCoverFeature(createForecastOrderBOS, createResponseList, taskId);
            }
        } catch (Exception e) {
            log.error("批量创建预报订单异常", e);
            throw new FunctionException("OC-04-001-01-16-001");
        }
        return createResponseList;
    }

    @NotNull
    private CommonAsyncMessageResponse buildCommonAsyncMessageResponse(AsyncMessageEventEnum eventEnum, String fromSys, String businessUnitCode, List createResponseList) {
        CommonAsyncMessageResponse commonAsyncMessageResponse = new CommonAsyncMessageResponse();
        commonAsyncMessageResponse.setEventCode(eventEnum.getValue());
        commonAsyncMessageResponse.setEventName(eventEnum.getLabel());
        commonAsyncMessageResponse.setEventTime(String.valueOf(new Date().getTime()));
        commonAsyncMessageResponse.setFromSys(fromSys);
        commonAsyncMessageResponse.setBusinessUnitCode(businessUnitCode);
        commonAsyncMessageResponse.setData(createResponseList);
        return commonAsyncMessageResponse;
    }

    @Override
    public Result<List<SubmitForecastResponseDTO>> batchSubmit(ForecastBizBatchSubmitRequest request) {
        List<SubmitForecastResponseDTO> responseDTOS = new ArrayList<>();
        List<SubmitForecastDTO> submitForecastDTOS = request.getSubmitForecastDTOS();

        //校验修改人
        String modifierCode = request.getModifierCode();
        Modifiers modifiers;
        try {
            StopWatchUtils.start("预报订单批量提交", "invalidModifier");
            modifiers = commonCheck.invalidModifier(modifierCode);
            StopWatchUtils.stop();
        } catch (FunctionException e) {
            throw e;
        } catch (Exception exception) {
            return Result.fail("OC-04-003-01-16-024", "预报订单批量提交失败");
        }
        List<String> bizOrderNOs = submitForecastDTOS.stream().map(SubmitForecastDTO::getSalesOrderNo).distinct().collect(Collectors.toList());

        StopWatchUtils.start("预报订单批量提交", "queryByOrderBizNo");
        List<ForecastOrderSDO> forecastOrderSDOS = forecastOrderQueryRepository.queryByOrderBizNo(bizOrderNOs, request.getForecastOrderTypeList());
        StopWatchUtils.stop();

        // 校验传入都预报订单是否都存在
        StopWatchUtils.start("预报订单批量提交", "notExistOrderBizIds");
        // if (forecastOrderSDOS.size() < bizOrderNOs.size()) {
        Set<String> existOrderBizIds = forecastOrderSDOS.stream().map(order -> String.format("%s_%s_%s_%s", order.getFromSys(), order.getBusinessType(), order.getBusinessUnitCode(), order.getOrderBizId())).collect(toSet());
        log.info("ForecastOrderBizWriteServiceImpl#Submit existOrderBizIds:{}", JSON.toJSONString(existOrderBizIds));
        // 【系统来源编码+业态编码+业务单元编码+预报单号】合并校验订单是否存在
        List<String> notExistOrderBizIds = bizOrderNOs.stream()
                .filter(bizOrderNO -> !existOrderBizIds.contains(String.format("%s_%s_%s_%s", request.getFromSys(), request.getBusinessType(), request.getBusinessUnitCode(), bizOrderNO)))
                .collect(Collectors.toList());
        log.info("ForecastOrderBizWriteServiceImpl#Submit notExistOrderBizIds:{}", JSON.toJSONString(notExistOrderBizIds));
        if (!CollectionUtils.isEmpty(notExistOrderBizIds)) {
            throw new FunctionException("OC-01-001-01-16-016", StringUtils.join(notExistOrderBizIds, "、"));
        }
        // }
        StopWatchUtils.stop();

        StopWatchUtils.start("预报订单批量提交", "invalidForecastStatus");
        for (ForecastOrderSDO forecastOrderSDO : forecastOrderSDOS) {
            invalidForecastStatus(forecastOrderSDO, ACTION_TYPE_SUBMIT);
        }
        StopWatchUtils.stop();

        //更新主子单至提交后状态
        StopWatchUtils.start("预报订单批量提交", "batchUpdateStatus");
        forecastOrderWriteRepository.batchUpdateStatus(forecastOrderSDOS, modifiers, responseDTOS);
        StopWatchUtils.stop();
        sendMsgService.sendForecastOrderChangeMsg(responseDTOS.stream().filter(SubmitForecastResponseDTO::getSuccess).map(SubmitForecastResponseDTO::getSalesOrderNo).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_COMMITED);
        return Result.success(responseDTOS);
    }

    @Override
    public Result<ModifyForecastResponseDTO> modify(ForecastOrderEntity forecastOrderEntity) {
        ForecastOrderBO forecastOrderBO = forecastOrderEntity.getForecastOrderBO();
        QueryBySourceNoRequest sourceNoRequest = new QueryBySourceNoRequest();
        sourceNoRequest.setOrderBizId(forecastOrderBO.getOrderBizId());
        sourceNoRequest.setFromSys(forecastOrderBO.getFromSys());
        sourceNoRequest.setUnitCode(forecastOrderBO.getBusinessUnitCode());
        sourceNoRequest.setBusinessTypeCode(forecastOrderBO.getBusinessType());
        sourceNoRequest.setOrderCategoryCode(forecastOrderBO.getOrderCategoryCode());
        StopWatchUtils.start("预报订单修改", "queryBySourceOrderNo");
        ForecastOrderSDO forecastOrderSDO = forecastOrderQueryRepository.queryBySourceOrderNo(sourceNoRequest);
        StopWatchUtils.stop();
        if (Objects.isNull(forecastOrderSDO)) {
            return Result.fail("OC-04-003-01-16-001", "预报单不存在");
        }

        //验证预报单状态
        try {
            String actionType = ACTION_TYPE_MODIFY;
            if (MapUtils.isNotEmpty(forecastOrderBO.getFeatures()) && (Boolean) forecastOrderBO.getFeatures().getOrDefault("allFieldNull", false)) {
                actionType = ACTION_TYPE_MODIFY_COMPLETE;
            }
            forecastOrderBO.setFeatures(null); // 清空features数据，防止db数据被覆盖
            invalidForecastStatus(forecastOrderSDO, actionType);
        } catch (FunctionException e) {
            return Result.fail(e.getErrorCode(), e.getErrorMessage());
        }

        //丰富缺省信息
        StopWatchUtils.start("预报订单修改", "enrichDefaultValue");
        forecastOrderBatchCreateAbility.enrichDefaultValue(forecastOrderBO, forecastOrderSDO);
        StopWatchUtils.stop();
        log.info("forecastOrderBO丰富后参数:{}", JSON.toJSONString(forecastOrderBO));

        //业务校验
        List<ForecastOrderBO> forecastOrderBOS = Lists.newArrayList(forecastOrderBO);
        List<CreateForecastResponseDTO> createResponseList = new ArrayList<>();
        StopWatchUtils.start("预报订单修改", "invalidMainData");
        forecastOrderBatchCreateAbility.invalidMainData(forecastOrderBOS, createResponseList, null);
        StopWatchUtils.stop();

        ModifyForecastResponseDTO modifyForecastResponseDTO = new ModifyForecastResponseDTO();
        if (CollectionUtils.isNotEmpty(forecastOrderBOS)) {
            try {
                StopWatchUtils.start("预报订单修改", "modify");
                forecastOrderEntity.modify(forecastOrderSDO);
            } catch (Throwable e) {
                log.error("创建预报单持久化异常", e);
                return Result.fail("OC-04-003-01-16-005", "预报订单修改失败");
            } finally {
                StopWatchUtils.stop();
            }
            modifyForecastResponseDTO.setForecastOrderBizNo(forecastOrderBO.getOrderBizId());
            modifyForecastResponseDTO.setSuccess(Boolean.TRUE);
            return Result.success(modifyForecastResponseDTO, "", "");
        }

        if (CollectionUtils.isNotEmpty(createResponseList)) {
            CreateForecastResponseDTO createForecastResponseDTO = createResponseList.get(0);
            BeanUtils.copyProperties(createForecastResponseDTO, modifyForecastResponseDTO);
        }

        return Result.fail(modifyForecastResponseDTO, "OC-04-003-01-16-005", "预报订单修改失败");
    }

    @Override
    @FacadeInvoker
    public Result<AnalysisForecastResponseDTO> batchAnalysis(AnalysisForecastRequest request) {
        BatchAnalysisOrdersRequest batchAnalysisOrdersRequest = new BatchAnalysisOrdersRequest();

        Modifiers modifier = commonCheck.invalidModifier(request.getModifierCode());
        //转换内部子单ID
        List<String> lineIds = exchangeInnerCode(request.getAnalysisForecastNoDTOList());
        batchAnalysisOrdersRequest.setIds(lineIds);
        batchAnalysisOrdersRequest.setModifierId(request.getModifierCode());
        batchAnalysisOrdersRequest.setModifierName(modifier.getName());
        batchAnalysisOrdersRequest.setType("onlyJoin");
        ApiContext apiContext = new ApiContext();
        apiContext.setEmployeeId(request.getModifierCode());
        apiContext.setEmployeeName(modifier.getName());
        batchAnalysisOrdersRequest.setApiContext(apiContext);

        try {
            Result<Boolean> result = forecastOrderWriteService.batchAnalysisOrders(batchAnalysisOrdersRequest);
            if (Objects.nonNull(result) && result.isSuccess()) {
                AnalysisForecastResponseDTO forecastResponseDTO = new AnalysisForecastResponseDTO();
                forecastResponseDTO.setBusinessType(request.getBusinessType());
                forecastResponseDTO.setBusinessUnitCode(request.getBusinessUnitCode());
                forecastResponseDTO.setBatchNo(result.getMessage());
                forecastResponseDTO.setFromSys(request.getFromSys());
                return Result.success(forecastResponseDTO);
            }
            log.error("批量分析失败", JSON.toJSONString(result));
            if ("SYS_ERR_ORDERLINE_ANALYZING".equals(result.getErrorCode())) {
                return Result.fail("OC-04-003-01-16-008", "预报订单正在分析中，请勿重复分析");
            }
            return Result.fail("OC-04-003-01-16-009", "预报订单批量分析失败");
        } catch (Throwable e) {
            log.error("批量分析异常", e);
            return Result.fail("OC-04-003-01-16-009", "预报订单批量分析失败");
        }
    }

    private List<String> exchangeInnerCode(List<AnalysisForecastBizDTO> analysisForecastNoDTOList) {
        ForecastOrderLineBizDO forecastOrderLineBizDO = AnalysisForecastBizDTOTODOConvert.convert(analysisForecastNoDTOList);
        Map<String, AnalysisForecastBizDTO> analysisForecastBizDTOMap = analysisForecastNoDTOList.stream().collect(Collectors.toMap(o -> o.getSalesOrderNo() + "-" + o.getLineNum(), Function.identity(), (v1, v2) -> v1));

        BatchQueryByBizDoListResponse batchQueryByBizDoListResponse = forecastOrderLineQueryRepository.queryByBizList(forecastOrderLineBizDO);
        if (Objects.nonNull(batchQueryByBizDoListResponse) && CollectionUtils.isNotEmpty(batchQueryByBizDoListResponse.getResult())) {
            List<ForecastOrderLineBizResponseDO> lineBizResponseDOS = batchQueryByBizDoListResponse.getResult();
            return lineBizResponseDOS.stream().filter(o -> {
                String key = o.getForecastOrderBizNo() + "-" + o.getLineNo();
                return analysisForecastBizDTOMap.containsKey(key);
            }).map(ForecastOrderLineBizResponseDO::getLineId).map(String::valueOf).distinct().collect(Collectors.toList());
        }
        throw new FacadeException("OC-04-003-01-16-001");
    }

    private void invalidForecastStatus(ForecastOrderSDO forecastOrderSDO, String actionType) {
        switch (actionType) {
            case ACTION_TYPE_SUBMIT:
                if (!forecastOrderSDO.getStatus().equals(ForecastStatusEnum.DRAFT.getNumValue())) {
                    throw new FunctionException("OC-04-002-01-16-001");
                }
                if (CollectionUtils.isEmpty(forecastOrderSDO.getForecastOrderLineSDOList())) {
                    throw new FunctionException("OC-04-002-01-16-003");
                }
                forecastOrderSDO.setStatus(ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue());
                break;
            case ACTION_TYPE_MODIFY:
                if (!(forecastOrderSDO.getStatus().equals(ForecastStatusEnum.DRAFT.getNumValue())
                        || forecastOrderSDO.getStatus().equals(ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue())
                        || forecastOrderSDO.getStatus().equals(ForecastStatusEnum.PARTIAL_REPLY.getNumValue()))) {
                    throw new FunctionException("OC-01-001-01-16-048");
                }
                break;
            case ACTION_TYPE_MODIFY_COMPLETE:
                if (!(forecastOrderSDO.getStatus().equals(ForecastStatusEnum.DRAFT.getNumValue())
                        || forecastOrderSDO.getStatus().equals(ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue())
                        || forecastOrderSDO.getStatus().equals(ForecastStatusEnum.PARTIAL_REPLY.getNumValue())
                        || forecastOrderSDO.getStatus().equals(ForecastStatusEnum.COMPLETED.getNumValue()))) {
                    throw new FunctionException("OC-01-001-01-16-048");
                }
                break;
            default:
                break;
        }
    }

    private void batchSave(List<ForecastOrderBO> forecastOrderBOS, List<CreateForecastResponseDTO> createResponseList, String taskId) {
        log.info("start forecast order save, batchId:{}, forecastOrderBOS:{}, createResponseList:{}",
                taskId, JSON.toJSONString(forecastOrderBOS), JSON.toJSONString(createResponseList));
        List<ForecastOrderEntity> forecastOrderEntities = ForecastOrderFactory.createBODraft(forecastOrderBOS);

        for (ForecastOrderEntity forecastOrderEntity : forecastOrderEntities) {
            ForecastOrderBO forecastOrderBO = forecastOrderEntity.getForecastOrderBO();
            try {
                forecastOrderEntity.create();
            } catch (FunctionException e) {
                CreateForecastResponseDTO forecastResponseDTO = new CreateForecastResponseDTO();
                forecastResponseDTO.setErrorCode(e.getErrorCode());
                forecastResponseDTO.setMessage(e.getMessage());
                forecastResponseDTO.setSuccess(Boolean.FALSE);
                forecastResponseDTO.setSourceOrderNo(forecastOrderBO.getSourceOrderNo());
                forecastResponseDTO.setReqNo(forecastOrderBO.getReqNo());
                forecastResponseDTO.setBatchTaskId(taskId);
                createResponseList.add(forecastResponseDTO);
                continue;
            } catch (Throwable throwable) {
                log.error("创建预报单异常", throwable);
            }

            String submitFlag = forecastOrderBO.getSubmitFlag();
            if (Boolean.TRUE.toString().equals(submitFlag)) {
                //是否提交
                try {
                    forecastOrderEntity.submit(forecastOrderBO.getCreatorId(), forecastOrderBO.getCreatorCode(), forecastOrderBO.getCreatorName());
                } catch (FunctionException e) {
                    CreateForecastResponseDTO forecastResponseDTO = new CreateForecastResponseDTO();
                    forecastResponseDTO.setErrorCode(e.getErrorCode());
                    forecastResponseDTO.setMessage(e.getMessage());
                    forecastResponseDTO.setReqNo(forecastOrderBO.getReqNo());
                    forecastResponseDTO.setBatchTaskId(taskId);
                    forecastResponseDTO.setSuccess(Boolean.FALSE);
                    createResponseList.add(forecastResponseDTO);
                    continue;
                } catch (Throwable throwable) {
                    log.error("提交预报单异常", throwable);
                }
            }

            CreateForecastResponseDTO forecastResponseDTO = ForecastOrderBOToResponseDTOConvertor.convert(forecastOrderBO);
            forecastResponseDTO.setBatchTaskId(taskId);
            forecastResponseDTO.setSuccess(Boolean.TRUE);
            createResponseList.add(forecastResponseDTO);
        }
    }

    private void batchSaveNotCoverFeature(List<ForecastOrderBO> forecastOrderBOS, List<CreateForecastResponseDTO> createResponseList, String taskId) {
        log.info("start forecast order save,batchId:{},Objects:{},existResp:{}", taskId, JSON.toJSONString(forecastOrderBOS), JSON.toJSONString(createResponseList));
        List<ForecastOrderEntity> forecastOrderEntities = ForecastOrderFactory.createBODraftNotCoverFeature(forecastOrderBOS);

        for (ForecastOrderEntity forecastOrderEntity : forecastOrderEntities) {
            ForecastOrderBO forecastOrderBO = forecastOrderEntity.getForecastOrderBO();
            try {
                forecastOrderEntity.create();
            } catch (FunctionException e) {
                CreateForecastResponseDTO forecastResponseDTO = new CreateForecastResponseDTO();
                forecastResponseDTO.setErrorCode(e.getErrorCode());
                forecastResponseDTO.setMessage(e.getMessage());
                forecastResponseDTO.setSuccess(Boolean.FALSE);
                forecastResponseDTO.setSourceOrderNo(forecastOrderBO.getSourceOrderNo());
                forecastResponseDTO.setReqNo(forecastOrderBO.getReqNo());
                forecastResponseDTO.setBatchTaskId(taskId);
                createResponseList.add(forecastResponseDTO);
                continue;
            } catch (Throwable throwable) {
                log.error("创建预报单异常", throwable);
            }

            String submitFlag = forecastOrderBO.getSubmitFlag();
            if (Boolean.TRUE.toString().equals(submitFlag)) {
                //是否提交
                try {
                    forecastOrderEntity.submit(forecastOrderBO.getCreatorId(), forecastOrderBO.getCreatorCode(), forecastOrderBO.getCreatorName());
                } catch (FunctionException e) {
                    CreateForecastResponseDTO forecastResponseDTO = new CreateForecastResponseDTO();
                    forecastResponseDTO.setErrorCode(e.getErrorCode());
                    forecastResponseDTO.setMessage(e.getMessage());
                    forecastResponseDTO.setReqNo(forecastOrderBO.getReqNo());
                    forecastResponseDTO.setBatchTaskId(taskId);
                    forecastResponseDTO.setSuccess(Boolean.FALSE);
                    createResponseList.add(forecastResponseDTO);
                    continue;
                } catch (Throwable throwable) {
                    log.error("提交预报单异常", throwable);
                }
            }

            CreateForecastResponseDTO forecastResponseDTO = ForecastOrderBOToResponseDTOConvertor.convert(forecastOrderBO);
            forecastResponseDTO.setBatchTaskId(taskId);
            forecastResponseDTO.setSuccess(Boolean.TRUE);
            createResponseList.add(forecastResponseDTO);
        }
    }

    @Override
    public Result<List<CancelForecastResponseDTO>> batchCancel(CancelForecastRequest request) {
        //校验修改人
        Map<String, Modifiers> modifiersMap;
        try {
            StopWatchUtils.start("预报订单批量取消", "invalidModifierList");
            List<String> modifierCodeList = request.getCancelForecastDTOS().stream().map(ForecastCancelRequest::getModifierCode).collect(Collectors.toList());
            modifiersMap = commonCheck.invalidModifierList(modifierCodeList);
            StopWatchUtils.stop();
        } catch (FunctionException e) {
            throw e;
        } catch (Exception exception) {
            return Result.fail("OC-04-003-01-16-024", "预报订单批量取消失败");
        }

        StopWatchUtils.start("预报订单批量取消", "queryByOrderBizNo");
        List<String> salesOrderNos = request.getCancelForecastDTOS().stream().map(ForecastCancelRequest::getSalesOrderNo).collect(Collectors.toList());
        List<ForecastOrderSDO> forecastOrderSDOs = forecastOrderQueryRepository.queryByOrderBizNo(salesOrderNos, request.getForecastOrderTypeList());
        log.info("ForecastOrderBizWriteServiceImpl#batchCancel byBizNoResponse:{}", JSON.toJSONString(forecastOrderSDOs));
        StopWatchUtils.stop();

        List<CancelForecastResponseDTO> responseDTOS = new ArrayList<>();
        if (CollectionUtils.isEmpty(forecastOrderSDOs)) {
            for (String x : salesOrderNos) {
                CancelForecastResponseDTO tmp = new CancelForecastResponseDTO();
                tmp.setSalesOrderNo(x);
                tmp.setMessage(ErrorMessage.code("OC-04-001-01-16-017").getDisplayErrorMessage());
                tmp.setSuccess(false);
                tmp.setErrorCode("OC-04-001-01-16-017");
                responseDTOS.add(tmp);
            }
            return Result.success(responseDTOS);
        }

        Map<String, ForecastOrderSDO> forecastOrderMap = forecastOrderSDOs.stream()
                .collect(Collectors.toMap(k -> String.format("%s_%s_%s_%s", k.getFromSys(), k.getBusinessType(), k.getBusinessUnitCode(), k.getOrderBizId()), o -> o, (x, y) -> x));

        Modifiers modifiers = modifiersMap.get(request.getCancelForecastDTOS().get(0).getModifierCode());
        List<String> forecastOrderIds = new ArrayList<>();
        Map<String, List<Long>> forecastOrderLineIdMap = new HashMap<>();
        for (ForecastCancelRequest x : request.getCancelForecastDTOS()) {
            try {
                ForecastOrderSDO forecastOrder = forecastOrderMap.get(String.format("%s_%s_%s_%s", request.getFromSys(), request.getBusinessType(), request.getBusinessUnitCode(), x.getSalesOrderNo()));
                CancelForecastResponseDTO tmp = new CancelForecastResponseDTO();
                tmp.setSalesOrderNo(x.getSalesOrderNo());
                if (forecastOrder == null) {
                    tmp.setMessage(ErrorMessage.code("OC-04-001-01-16-017").getDisplayErrorMessage());
                    tmp.setSuccess(false);
                    tmp.setErrorCode("OC-04-001-01-16-017");
                    responseDTOS.add(tmp);
                    continue;
                }

                //仅待提交&待回复状态下的预报订单支持取消，如果非待提交&待回复状态订单，提示“非待提交或待回复”状态不允许取消
                if (!(ForecastStatusEnum.DRAFT.getNumValue().equals(forecastOrder.getStatus())
                        || ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue().equals(forecastOrder.getStatus()))) {
                    tmp.setMessage(ErrorMessage.code("OC-01-001-01-16-053").getDisplayErrorMessage());
                    tmp.setSuccess(false);
                    tmp.setErrorCode("OC-01-001-01-16-053");
                } else {
                    tmp.setSuccess(true);
                    forecastOrderIds.add(forecastOrder.getId());

                    // 根据关闭原因分组进行关闭
                    String cancelCode = Optional.ofNullable(x.getCancelCode()).orElse("");
                    List<Long> forecastOrderLineIds;
                    if (forecastOrderLineIdMap.containsKey(cancelCode)) {
                        forecastOrderLineIds = forecastOrderLineIdMap.get(cancelCode);
                    } else {
                        forecastOrderLineIds = new ArrayList<>();
                    }
                    for (ForecastOrderLineSDO forecastOrderLineSDO : forecastOrder.getForecastOrderLineSDOList()) {
                        forecastOrderLineIds.add(forecastOrderLineSDO.getId());
                    }
                    forecastOrderLineIdMap.put(cancelCode, forecastOrderLineIds);
                }
                responseDTOS.add(tmp);
            } catch (Exception e) {
                log.error("ForecastOrderBizWriteServiceImpl#batchCancel updateOrder error", e);
                throw e;
            }
        }

        StopWatchUtils.start("预报订单批量取消", "batchUpdateStatusByIds");
        try {
            // 批量取消预报主单
            BatchUpdateStatusByIdsRequest batchUpdateStatusByIdsRequest = new BatchUpdateStatusByIdsRequest();
            batchUpdateStatusByIdsRequest.setIds(forecastOrderIds);
            batchUpdateStatusByIdsRequest.setStatus(ForecastStatusEnum.CANCELLED.getNumValue());
            batchUpdateStatusByIdsRequest.setModifierId(modifiers.getId());
            batchUpdateStatusByIdsRequest.setModifierCode(modifiers.getWorkId());
            batchUpdateStatusByIdsRequest.setModifierName(modifiers.getName());
            forecastOrderService.batchUpdateStatusByIds(batchUpdateStatusByIdsRequest);
        } catch (Exception e) {
            log.error("ForecastOrderBizWriteServiceImpl#batchCancel batchUpdateStatusByIds error", e);
        }
        StopWatchUtils.stop();

        StopWatchUtils.start("预报订单批量取消", "batchUpdateForClose");
        batchUpdateForClose(forecastOrderLineIdMap, GeneralStatusEnum.NO.getCode(), ForecastStatusEnum.CANCELLED.getNumValue());
        StopWatchUtils.stop();

        sendMsgService.sendForecastOrderChangeMsg(responseDTOS.stream().filter(CancelForecastResponseDTO::getSuccess).map(CancelForecastResponseDTO::getSalesOrderNo).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_CANCEL);

        return Result.success(responseDTOS);
    }

    /**
     * 批量修改预报订单明细状态和拒绝原因
     */
    private void batchUpdateForClose(Map<String, List<Long>> forecastOrderLineIdMap, Integer closed, Integer lineStatus) {
        if (MapUtils.isEmpty(forecastOrderLineIdMap)) {
            return;
        }
        try {
            // 批量取消预报明细
            forecastOrderLineIdMap.forEach((refuseReasonCode, orderLineIds) -> {
                BatchUpdateForCloseRequest batchUpdateForCloseRequest = new BatchUpdateForCloseRequest();
                batchUpdateForCloseRequest.setOrderLineIds(orderLineIds);
                batchUpdateForCloseRequest.setClosed(closed);
                batchUpdateForCloseRequest.setLineStatus(lineStatus);
                batchUpdateForCloseRequest.setRefuseReasonCode(refuseReasonCode);
                batchUpdateForCloseRequest.setRefuseReason(SalesOrderCloseEnum.descByCode(refuseReasonCode));
                log.info("ForecastOrderBizWriteServiceImpl#batchUpdateForClose batchUpdateForCloseRequest={}", JSON.toJSONString(batchUpdateForCloseRequest));
                forecastOrderLineWriteRepository.batchUpdateForClose(batchUpdateForCloseRequest);
            });
        } catch (Exception e) {
            log.error("ForecastOrderBizWriteServiceImpl#batchUpdateForClose error", e);
            throw e;
        }
    }

    @Override
    public Result<List<ForecastReplyBizModifyResponse>> batchModifyReply(ForecastReplyBizBatchModifyRequest request) {
        // 初始化修改人信息
        StopWatchUtils.start("预报订单回复批量修改", "getModifierCode");
        String modifierCode = request.getModifierCode();
        Modifiers modifier = commonCheck.invalidModifier(modifierCode);
        StopWatchUtils.stop();

        StopWatchUtils.start("预报订单回复批量修改", "queryByOrderBizNo");
        List<String> salesOrderNos = request.getOrderList().stream().map(ForecastReplyBizModifyRequest::getSalesOrderNo).distinct().collect(Collectors.toList());
        List<ForecastOrderSDO> forecastOrderSDOS = forecastOrderQueryRepository.queryByOrderBizNo(salesOrderNos, request.getForecastOrderTypeList());
        StopWatchUtils.stop();
        if (CollectionUtils.isEmpty(forecastOrderSDOS)) {
            return Result.fail("OC-04-003-01-16-001", "预报订单不存在");
        }

        // 根据 预报订单单号 缓存订单
        Map<String, ForecastOrderSDO> forecastOrderSDOMap = new HashMap<>();
        // 根据 预报订单单号+行号 缓存订单行
        Map<String, ForecastOrderLineSDO> forecastOrderLineSDOMap = new HashMap<>();
        for (ForecastOrderSDO forecastOrderSDO : forecastOrderSDOS) {
            forecastOrderSDOMap.put(forecastOrderSDO.getOrderBizId(), forecastOrderSDO);
            for (ForecastOrderLineSDO forecastOrderLineSDO : forecastOrderSDO.getForecastOrderLineSDOList()) {
                String key = String.format("%s_%s_%s_%s_%s", forecastOrderSDO.getFromSys(), forecastOrderSDO.getBusinessType(),
                        forecastOrderSDO.getBusinessUnitCode(), forecastOrderSDO.getOrderBizId(), forecastOrderLineSDO.getSerialNumber());
                forecastOrderLineSDOMap.put(key, forecastOrderLineSDO);
            }
        }

        List<ForecastReplyBizModifyResponse> responses = Collections.synchronizedList(new ArrayList<>());
        StopWatchUtils.start("预报订单回复批量修改", "doModifyReply");
        this.doModifyReply(request, responses, modifier, forecastOrderSDOMap, forecastOrderLineSDOMap);
        StopWatchUtils.stop();
        Set<Boolean> successSet = responses.stream().map(ForecastReplyBizModifyResponse::getSuccess).collect(toSet());
        if (successSet.contains(Boolean.FALSE)) {
            return Result.fail(responses, "OC-04-003-01-16-005", "预报订单修改失败");
        }
        return Result.success(responses);
    }

    private void doModifyReply(ForecastReplyBizBatchModifyRequest request,
                               List<ForecastReplyBizModifyResponse> responses,
                               Modifiers modifier,
                               Map<String, ForecastOrderSDO> forecastOrderSDOMap,
                               Map<String, ForecastOrderLineSDO> forecastOrderLineSDOMap) {

        CountDownLatch countDownLatch = new CountDownLatch(request.getOrderList().size());
        for (ForecastReplyBizModifyRequest modifyRequest : request.getOrderList()) {
            ThreadPoolUtil.execute(() -> {
                try {
                    ForecastReplyBizModifyResponse response = ForecastReplyBizModifyResponse.builder()
                            .salesOrderNo(modifyRequest.getSalesOrderNo())
                            .lineNum(modifyRequest.getLineNum())
                            .build();

                    ForecastOrderSDO forecastOrderSDO = forecastOrderSDOMap.get(modifyRequest.getSalesOrderNo());
                    // 存在性校验
                    if (Objects.isNull(forecastOrderSDO)) {
                        response.setErrorCode("OC-04-003-01-16-001");
                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                        response.setSuccess(Boolean.FALSE);
                        responses.add(response);
                        return;
                    }
                    // 判断来源是否相同
                    boolean sameSource = Objects.equals(forecastOrderSDO.getFromSys(), request.getFromSys())
                            && Objects.equals(forecastOrderSDO.getBusinessType(), request.getBusinessType())
                            && Objects.equals(forecastOrderSDO.getBusinessUnitCode(), request.getBusinessUnitCode());
                    if (!sameSource) {
                        response.setErrorCode("OC-04-003-01-16-001");
                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                        response.setSuccess(Boolean.FALSE);
                        responses.add(response);
                        return;
                    }
                    // 系统来源编码+业态编码+业务单元编码+中台预报单号+中台预报订单明细行号
                    String key = String.format("%s_%s_%s_%s_%s", request.getFromSys(), request.getBusinessType(),
                            request.getBusinessUnitCode(), modifyRequest.getSalesOrderNo(), modifyRequest.getLineNum());
                    ForecastOrderLineSDO forecastOrderLineSDO = forecastOrderLineSDOMap.get(key);
                    // 存在性校验
                    if (Objects.isNull(forecastOrderLineSDO)) {
                        response.setErrorCode("OC-04-003-01-16-002");
                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                        response.setSuccess(Boolean.FALSE);
                        responses.add(response);
                        return;
                    }
                    // 状态校验，仅支持修改待回复、部分回复订单
                    if (!ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue().equals(forecastOrderLineSDO.getStatus())
                            && !ForecastStatusEnum.PARTIAL_REPLY.getNumValue().equals(forecastOrderLineSDO.getStatus())) {
                        response.setErrorCode("OC-01-001-01-16-053");
                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                        response.setSuccess(Boolean.FALSE);
                        responses.add(response);
                        return;
                    }

                    try {
                        int predictReplyAmount = Integer.parseInt(modifyRequest.getPredictReplyAmount());
                        if (predictReplyAmount <= 0) {
                            response.setErrorCode("OC-01-001-01-15-005");
                            response.setMessage(ErrorMessage.code(response.getErrorCode(), "预计回复数量").getDisplayErrorMessage());
                            response.setSuccess(Boolean.FALSE);
                            responses.add(response);
                            return;
                        }
                        forecastOrderLineSDO.setPredictReplyAmount(predictReplyAmount);
                        if (StringUtils.isNotBlank(modifyRequest.getBizFeatures())) {
                            forecastOrderLineSDO.setBizFeatures(modifyRequest.getBizFeatures());
                        }
                    } catch (Exception e) {
                        log.error("ForecastOrderBizWriteServiceImpl#batchModifyReply parseInt error", e);
                        response.setErrorCode("OC-00-001-01-15-001");
                        response.setMessage(ErrorMessage.code(response.getErrorCode(), "预计回复数量").getDisplayErrorMessage());
                        response.setSuccess(Boolean.FALSE);
                        responses.add(response);
                        return;
                    }

                    try {
                        BatchUpdateForAnalysisDTO batchUpdateForAnalysisDTO = new BatchUpdateForAnalysisDTO();
                        batchUpdateForAnalysisDTO.setPredictReplyAmount(forecastOrderLineSDO.getPredictReplyAmount());
                        batchUpdateForAnalysisDTO.setModifierId(modifier.getId());
                        batchUpdateForAnalysisDTO.setModifierCode(modifier.getWorkId());
                        batchUpdateForAnalysisDTO.setModifierName(modifier.getName());
                        batchUpdateForAnalysisDTO.setBizFeatures(forecastOrderLineSDO.getBizFeatures());
                        batchUpdateForAnalysisDTO.setBizOrderId(forecastOrderLineSDO.getMainOrderBizId());
                        batchUpdateForAnalysisDTO.setLineNo(forecastOrderLineSDO.getSerialNumber());
                        log.info("ForecastOrderBizWriteServiceImpl#batchModifyReply forecastOrderLineSDO:{}; batchUpdateForAnalysisDTO:{}", forecastOrderLineSDO, batchUpdateForAnalysisDTO);
                        Boolean updateResult = forecastOrderLineWriteRepository.updateForAnalysis(batchUpdateForAnalysisDTO);
                        if (updateResult) {
                            // 修改成功直接跳过
                            response.setSuccess(Boolean.TRUE);
                            responses.add(response);
                            return;
                        }
                        response.setErrorCode("OC-04-003-01-16-010");
                    } catch (Exception e) {
                        log.error("ForecastOrderBizWriteServiceImpl#batchModifyReply error", e);
                        response.setErrorCode("OC-04-003-01-16-010");
                    }
                    if (StringUtils.isBlank(response.getErrorCode())) {
                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                        response.setSuccess(Boolean.FALSE);
                    }
                    responses.add(response);

                } catch (Exception e) {
                    log.error("ForecastOrderBizWriteServiceImpl#batchModifyReply error", e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }

        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("ForecastOrderBizWriteServiceImpl#batchModifyReply await error", e);
        }
    }

    @Override
    public void batchConfirm(ConfirmReplyRequest request) {

        List<ConfirmReplyResponseDTO> responseDTOS = new ArrayList<>();
        List<String> lineIds = exchangeBizForecast(request, request.getTaskId(), responseDTOS);
        if (CollectionUtils.isNotEmpty(lineIds)) {
            try {
                Modifiers modifier = commonCheck.invalidModifier(request.getModifierCode());
                BatchConfirmForecastBiz confirmForecastRequest = buildBatchConfirmForecastBiz(request, lineIds, modifier);
                Result<List<ConfirmForecastDTO>> listResult = forecastOrderWriteService.batchConfirmForecastBiz(confirmForecastRequest);
                if (Objects.nonNull(listResult) && CollectionUtils.isNotEmpty(listResult.getResult())) {
                    for (ConfirmForecastDTO confirmForecastDTO : listResult.getResult()) {
                        ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.convert(confirmForecastDTO);
                        replyResponseDTO.setBatchTaskId(request.getTaskId());
                        responseDTOS.add(replyResponseDTO);
                    }
                }
                // 发消息通知其它中心
                sendMsgService.sendForecastOrderChangeMsg(responseDTOS.stream().filter(ConfirmReplyResponseDTO::getSuccess).map(ConfirmReplyResponseDTO::getSalesOrderNo).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_CONFIRMED);
            } catch (FunctionException e) {
                log.error("ForecastOrderBizWriteServiceImpl#batchConfirm error", e);
                ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse(
                        e.getErrorCode(), e.getMessage(), Boolean.FALSE, request.getTaskId());
                responseDTOS.add(replyResponseDTO);
            } catch (Exception e) {
                log.error("ForecastOrderBizWriteServiceImpl#batchConfirm error", e);
                ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse(
                        "OC-04-005-01-16-001", "预报订单批量确认失败", Boolean.FALSE, request.getTaskId());
                responseDTOS.add(replyResponseDTO);
            }
        }

        //返回异步消息
        CommonAsyncMessageResponse response = buildCommonAsyncMessageResponse(AsyncMessageEventEnum.FORECAST_ORDER_CONFIRM, request.getFromSys(), request.getBusinessUnitCode(), responseDTOS);
        String messageKey = KafkaUtils.generateMessageKey(request.getFromSys(), "", request.getBusinessUnitCode(), response.getEventCode());
        log.info("ForecastOrderBizWriteServiceImpl#batchConfirm response={}", JSON.toJSONString(response));
        SendResult<Integer, String> sendResult = KafkaUtils.send(MnOrderCenterConstants.MN_KAFKA_TOPIC(), messageKey, JSON.toJSONString(response));
        log.info("ForecastOrderBizWriteServiceImpl#batchConfirm sendResult={}", sendResult);
    }


    @Override
    public List<ConfirmReplyResponseDTO> batchGroupConfirm(ConfirmGroupReplyRequest request){

        List<ConfirmReplyResponseDTO> responseDTOS = new ArrayList<>();
        List<String> lineIds = exchangeGroupForecast(request, responseDTOS);
        if (CollectionUtils.isNotEmpty(lineIds)) {
            try {
                Modifiers modifier = commonCheck.invalidModifier(request.getModifierCode());
                BatchConfirmForecastBiz confirmForecastRequest = buildBatchConfirmGroupForecastBiz(request, lineIds, modifier);
                Result<List<ConfirmForecastDTO>> listResult = forecastOrderWriteService.batchConfirmForecastGroupBiz(confirmForecastRequest);
                if (listResult.isSuccess()) {
                    sendMsgService.sendForecastOrderChangeMsg(listResult.getResult().stream().filter(ConfirmForecastDTO::getSuccess).map(ConfirmForecastDTO::getForecastOrderBizNO).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_CONFIRMED);
                }
                if (Objects.nonNull(listResult) && CollectionUtils.isNotEmpty(listResult.getResult())) {
                    for (ConfirmForecastDTO confirmForecastDTO : listResult.getResult()) {
                        ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.convert(confirmForecastDTO);
                        responseDTOS.add(replyResponseDTO);
                    }
                }
            } catch (FunctionException e) {
                log.error("ForecastOrderBizWriteServiceImpl#batchGroupConfirm error", e);
                ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse(
                        e.getErrorCode(), e.getMessage(), Boolean.FALSE, null);
                responseDTOS.add(replyResponseDTO);
                throw e;
            } catch (Exception e) {
                log.error("ForecastOrderBizWriteServiceImpl#batchGroupConfirm error", e);
                ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse(
                        "OC-04-005-01-16-001", "预报订单批量确认失败", Boolean.FALSE, null);
                responseDTOS.add(replyResponseDTO);
            }
        }
        log.info("responseDTOS业务结果:{}",JSON.toJSONString(responseDTOS));
        return responseDTOS;
    }



    @Override
    public List<ConfirmReplyResponseDTO> batchConfirmWithReturn(ConfirmReplyRequest confirmReplyRequest) {
        log.info("batchConfirmWithReturn param:{}" + JSON.toJSONString(confirmReplyRequest));
        List<ConfirmReplyResponseDTO> responseDTOS = new ArrayList<>();
        List<String> lineIds = exchangeInnerForecast(confirmReplyRequest.getConfirmReplyList(), confirmReplyRequest.getTaskId(), responseDTOS);
        if (CollectionUtils.isNotEmpty(lineIds)) {
            try {
                Modifiers modifier = commonCheck.invalidModifier(confirmReplyRequest.getModifierCode());

                BatchConfirmForecastBiz confirmForecastRequest = buildBatchConfirmForecastBiz(confirmReplyRequest, lineIds, modifier);
                Result<List<ConfirmForecastDTO>> listResult = forecastOrderWriteService.batchConfirmForecastBiz(confirmForecastRequest);
                if (Objects.nonNull(listResult) && CollectionUtils.isNotEmpty(listResult.getResult())) {
                    for (ConfirmForecastDTO confirmForecastDTO : listResult.getResult()) {
                        ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.convert(confirmForecastDTO);
                        replyResponseDTO.setBatchTaskId(confirmReplyRequest.getTaskId());
                        responseDTOS.add(replyResponseDTO);
                    }
                }
            } catch (FunctionException e) {
                log.error("批量确认异常", e);
                ConfirmReplyResponseDTO confirmReplyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse(e.getErrorCode(), e.getMessage(), Boolean.FALSE, confirmReplyRequest.getTaskId());
                responseDTOS.add(confirmReplyResponseDTO);
            } catch (Exception exception) {
                log.error("预报订单批量确认失败", exception);
                ConfirmReplyResponseDTO confirmReplyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse("OC-04-005-01-16-001"
                        , "预报订单批量确认失败", Boolean.FALSE, confirmReplyRequest.getTaskId());
                responseDTOS.add(confirmReplyResponseDTO);
            }
        }
        log.info("batchConfirmWithReturn result:{}", JSON.toJSONString(responseDTOS));
        // sendMsgService.sendForecastOrderChangeMsg(responseDTOS.stream().filter(ConfirmReplyResponseDTO::getSuccess).map(ConfirmReplyResponseDTO::getSalesOrderNo).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_CONFIRMED);
        return responseDTOS;
    }

    @Override
    public List<ConfirmReplyResponseDTO> syncBatchConfirmWith(ConfirmReplyFulfillRequest request) {
        log.info("syncBatchConfirmWith param:{}" + JSON.toJSONString(request));
        List<ConfirmReplyResponseDTO> responseDTOS = new ArrayList<>();
        ConfirmReplyRequest confirmReplyRequest = new ConfirmReplyRequest();
        BeanUtils.copyProperties(request, confirmReplyRequest);
        List<String> lineIds = exchangeInnerForecast(confirmReplyRequest.getConfirmReplyList(), request.getTaskId(), responseDTOS);
        if (CollectionUtils.isNotEmpty(lineIds)) {
            try {
                Modifiers modifier = commonCheck.invalidModifier(request.getModifierCode());

                SyncBatchConfirmForecastBiz confirmForecastRequest = buildSyncBatchConfirmForecastBiz(request, lineIds, modifier);
                Result<List<ConfirmForecastDTO>> listResult = forecastOrderWriteService.syncBatchConfirmForecastBiz(confirmForecastRequest);
                if (Objects.nonNull(listResult) && CollectionUtils.isNotEmpty(listResult.getResult())) {
                    for (ConfirmForecastDTO confirmForecastDTO : listResult.getResult()) {
                        ConfirmReplyResponseDTO replyResponseDTO = ConfirmDTOInnerToOuterConvert.convert(confirmForecastDTO);
                        replyResponseDTO.setBatchTaskId(request.getTaskId());
                        responseDTOS.add(replyResponseDTO);
                    }
                }
            } catch (FunctionException e) {
                log.error("批量确认异常", e);
                ConfirmReplyResponseDTO confirmReplyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse(e.getErrorCode(), e.getMessage(), Boolean.FALSE, request.getTaskId());
                responseDTOS.add(confirmReplyResponseDTO);
            } catch (Exception exception) {
                log.error("预报订单批量确认失败", exception);
                ConfirmReplyResponseDTO confirmReplyResponseDTO = ConfirmDTOInnerToOuterConvert.buildErrorResponse("OC-04-005-01-16-001"
                        , "预报订单批量确认失败", Boolean.FALSE, request.getTaskId());
                responseDTOS.add(confirmReplyResponseDTO);
            }
        }
        log.info("syncBatchConfirmWith result:{}", JSON.toJSONString(responseDTOS));
        sendMsgService.sendForecastOrderChangeMsg(responseDTOS.stream().filter(ConfirmReplyResponseDTO::getSuccess).map(ConfirmReplyResponseDTO::getSalesOrderNo).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_CONFIRMED);
        return responseDTOS;
    }

    @NotNull
    private BatchConfirmForecastBiz buildBatchConfirmForecastBiz(ConfirmReplyRequest confirmReplyRequest, List<String> lineIds, Modifiers modifier) {
        BatchConfirmForecastBiz confirmForecastRequest = new BatchConfirmForecastBiz();
        confirmForecastRequest.setIds(lineIds);
        confirmForecastRequest.setSequenceNo(confirmReplyRequest.getTaskId());
        confirmForecastRequest.setModifierName(modifier.getName());
        confirmForecastRequest.setModifierId(modifier.getId());
        confirmForecastRequest.setModifierCode(modifier.getWorkId());
        return confirmForecastRequest;
    }

    @NotNull
    private SyncBatchConfirmForecastBiz buildSyncBatchConfirmForecastBiz(ConfirmReplyFulfillRequest confirmReplyRequest, List<String> lineIds, Modifiers modifier) {
        SyncBatchConfirmForecastBiz confirmForecastRequest = new SyncBatchConfirmForecastBiz();
        confirmForecastRequest.setIds(lineIds);
        HashMap<String, String> fulfillMapping =  new HashMap<>();
        if (CollectionUtils.isNotEmpty(confirmReplyRequest.getConfirmReplyList())){
            for (ConfirmForecastReplyFulfillDTO confirmForecastReplyFulfillDTO : confirmReplyRequest.getConfirmReplyList()) {
                fulfillMapping.put(confirmForecastReplyFulfillDTO.getSalesOrderNo(),confirmForecastReplyFulfillDTO.getFulfillmentTypeCode());
            }
        }
        confirmForecastRequest.setFulfillmentMap(fulfillMapping);
        confirmForecastRequest.setSequenceNo(confirmReplyRequest.getTaskId());
        confirmForecastRequest.setModifierName(modifier.getName());
        confirmForecastRequest.setModifierId(modifier.getId());
        confirmForecastRequest.setModifierCode(modifier.getWorkId());
        return confirmForecastRequest;
    }

    @NotNull
    private BatchConfirmForecastBiz buildBatchConfirmGroupForecastBiz(ConfirmGroupReplyRequest confirmReplyRequest, List<String> lineIds, Modifiers modifier) {
        BatchConfirmForecastBiz confirmForecastRequest = new BatchConfirmForecastBiz();
        confirmForecastRequest.setIds(lineIds);
        confirmForecastRequest.setModifierName(modifier.getName());
        confirmForecastRequest.setModifierId(modifier.getId());
        confirmForecastRequest.setModifierCode(modifier.getWorkId());
        return confirmForecastRequest;
    }

    @Override
    @FacadeInvoker
    public Result<List<ForecastOrderBizCloseResponse>> batchClose(ForecastOrderBizBatchCloseRequest request) {
        StopWatchUtils.start("预报订单批量关闭", "invalidModifier");
        // 初始化修改人信息
        String modifierCode = request.getModifierCode();
        Modifiers modifier = commonCheck.invalidModifier(modifierCode);
        StopWatchUtils.stop();

        StopWatchUtils.start("预报订单批量关闭", "queryByOrderBizNo");
        List<String> salesOrderNos = request.getOrderList().stream().map(ForecastOrderBizCloseRequest::getSalesOrderNo).distinct().collect(Collectors.toList());
        List<ForecastOrderSDO> forecastOrderSDOS = forecastOrderQueryRepository.queryByOrderBizNo(salesOrderNos, request.getForecastOrderTypeList());
        StopWatchUtils.stop();
        if (CollectionUtils.isEmpty(forecastOrderSDOS)) {
            return Result.fail("OC-04-003-01-16-001", "预报订单不存在");
        }

        // 根据 预报订单单号 缓存订单
        Map<String, ForecastOrderSDO> forecastOrderSDOMap = new HashMap<>();
        // 根据 预报订单单号+行号 缓存订单行
        Map<String, ForecastOrderLineSDO> forecastOrderLineSDOMap = new HashMap<>();

        for (ForecastOrderSDO forecastOrderSDO : forecastOrderSDOS) {
            forecastOrderSDOMap.put(forecastOrderSDO.getOrderBizId(), forecastOrderSDO);
            for (ForecastOrderLineSDO forecastOrderLineSDO : forecastOrderSDO.getForecastOrderLineSDOList()) {
                // 系统来源编码+业态编码+业务单元编码+中台预报单号+中台预报订单明细行号
                String key = String.format("%s_%s_%s_%s_%s", forecastOrderSDO.getFromSys(), forecastOrderSDO.getBusinessType(), forecastOrderSDO.getBusinessUnitCode(),
                        forecastOrderSDO.getOrderBizId(), forecastOrderLineSDO.getSerialNumber());
                forecastOrderLineSDOMap.put(key, forecastOrderLineSDO);
            }
        }

        List<ForecastOrderSDO> toUpdateOrderList = new ArrayList<>();
        List<ForecastOrderLineSDO> toUpdateOrderLineList = new ArrayList<>();
        List<ForecastOrderBizCloseResponse> responses = new ArrayList<>();
        // 通知SAP的List对象
        Map<ForecastOrderSDO, List<ForecastOrderLineSDO>> sapParamMap = new HashMap<>();
        for (ForecastOrderBizCloseRequest closeRequest : request.getOrderList()) {
            ForecastOrderBizCloseResponse response = ForecastOrderBizCloseResponse.builder()
                    .salesOrderNo(closeRequest.getSalesOrderNo())
                    .lineNum(closeRequest.getLineNum())
                    .success(false)
                    .build();

            ForecastOrderSDO forecastOrderSDO = forecastOrderSDOMap.get(closeRequest.getSalesOrderNo());
            // 存在性校验
            if (Objects.isNull(forecastOrderSDO)) {
                response.setErrorCode("OC-04-003-01-16-001");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                responses.add(response);
                continue;
            }
            // 判断来源是否相同
            boolean sameSource = Objects.equals(forecastOrderSDO.getFromSys(), request.getFromSys())
                    && Objects.equals(forecastOrderSDO.getBusinessType(), request.getBusinessType())
                    && Objects.equals(forecastOrderSDO.getBusinessUnitCode(), request.getBusinessUnitCode());
            if (!sameSource) {
                response.setErrorCode("OC-04-003-01-16-001");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                responses.add(response);
                continue;
            }

            String key = String.format("%s_%s_%s_%s_%s", request.getFromSys(), request.getBusinessType(), request.getBusinessUnitCode(),
                    closeRequest.getSalesOrderNo(), closeRequest.getLineNum());
            ForecastOrderLineSDO forecastOrderLineSDO = forecastOrderLineSDOMap.get(key);
            // 存在性校验
            if (Objects.isNull(forecastOrderLineSDO)) {
                response.setErrorCode("OC-04-003-01-16-002");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                responses.add(response);
                continue;
            }
            // 状态校验
            if (!ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue().equals(forecastOrderLineSDO.getStatus())
                    && !ForecastStatusEnum.PARTIAL_REPLY.getNumValue().equals(forecastOrderLineSDO.getStatus())) {
                response.setErrorCode("OC-01-001-01-16-053");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                responses.add(response);
                continue;
            }

            // 加入待修改列表里，后面统一更新
            forecastOrderLineSDO.setRefuseReasonCode(closeRequest.getCloseCode());
            forecastOrderLineSDO.setRefuseReason(SalesOrderCloseEnum.descByCode(closeRequest.getCloseCode()));
            forecastOrderLineSDO.setModifierId(modifier.getId());
            forecastOrderLineSDO.setModifierName(modifier.getName());
            forecastOrderLineSDO.setModofierCode(modifier.getWorkId());
            toUpdateOrderLineList.add(forecastOrderLineSDO);

            forecastOrderSDO.setModifierId(modifier.getId());
            forecastOrderSDO.setModifierName(modifier.getName());
            forecastOrderSDO.setModifierCode(modifier.getWorkId());

            toUpdateOrderList.add(forecastOrderSDO);
            response.setSuccess(true);
            responses.add(response);
        }

        // 更新预报订单行状态
        StopWatchUtils.start("预报订单批量关闭", "updateOrderLineStatus");
        this.updateOrderLineStatus(toUpdateOrderLineList);
        StopWatchUtils.stop();

        // 更新预报订单状态
        StopWatchUtils.start("预报订单批量关闭", "updateOrderStatus");
        this.updateOrderStatus(toUpdateOrderList);
        StopWatchUtils.stop();

        // 1、区分是否是SAP给的预报订单，是SAP创建的才调sap关闭（外部单号） 2、调完SAP肯定会有一个callBack
        // bcLinkAdapter 直接通知SAP，无需关心callBack
        // 封装需要通知SAP的主单及子单（SAP预报单号是否存在）
        Map<String, ForecastOrderSDO> orderIdMap = toUpdateOrderList.stream().collect(toMap(ForecastOrderSDO::getId, v -> v, (k1, k2) -> k1));
        Map<String, List<ForecastOrderLineSDO>> forecastOrderLineMap = toUpdateOrderLineList.stream().collect(groupingBy(ForecastOrderLineSDO::getMainOrderId));
        orderIdMap.forEach((key, forecastOrderSDO) -> {
            if (StringUtils.isNotBlank(forecastOrderSDO.getOuterOrderId())) {
                // 组装SAP入参数据
                sapParamMap.put(forecastOrderSDO, forecastOrderLineMap.get(key));
            }
        });
        bcLinkAdapter.forecastClosedToSap(sapParamMap);
        sendMsgService.sendForecastOrderChangeMsg(toUpdateOrderList.stream().map(ForecastOrderSDO::getOrderBizId).collect(toList()), InnerMessageEventEnum.FORECAST_ORDER_CLOSED);
        return Result.success(responses);
    }

    @Override
    public Result<List<ForecastOrderBizModifyActivityResponse>> batchModifyActivity(ForecastOrderBizBatchModifyActivityRequest request) {
        List<String> salesOrderNos = request.getActivityList().stream().map(ForecastOrderBizModifyActivityRequest::getSalesOrderNo).distinct().collect(Collectors.toList());
        List<ForecastOrderBizModifyActivityResponse> responses = new ArrayList<>();
        BatchQueryForecastByBizNoRequest batchQueryForecastByBizNoRequest = new BatchQueryForecastByBizNoRequest();
        batchQueryForecastByBizNoRequest.setBizNoList(salesOrderNos);
        batchQueryForecastByBizNoRequest.setFromSys(request.getFromSys());
        batchQueryForecastByBizNoRequest.setBusinessType(request.getBusinessType());
        batchQueryForecastByBizNoRequest.setBusinessUnitCode(request.getBusinessUnitCode());
        List<ForecastOrderSDO> forecastOrderSDOS = forecastOrderQueryRepository.queryByOrderBizNoWithBizCode(batchQueryForecastByBizNoRequest);
        if (CollectionUtils.isEmpty(forecastOrderSDOS)) {
            return Result.fail("OC-04-003-01-16-001", "预报订单不存在");
        }

        String modifierCode = request.getModifierCode();
        Modifiers modifier;
        try {
            modifier = commonCheck.invalidModifier(modifierCode);
        } catch (FunctionException e) {
            return Result.fail("OC-01-001-01-16-041", "人员不存在");
        } catch (Exception exception) {
            return Result.fail("OC-04-003-01-16-023", "预报订单批量修改活动失败");
        }

        log.info("ForecastOrderBizServiceImpl#batchModifyActivity forecastOrderSDOS={}", JSON.toJSONString(forecastOrderSDOS));
        // 根据 预报订单单号 缓存订单
        Map<String, ForecastOrderSDO> forecastOrderSDOMap = new HashMap<>();
        // 根据 预报订单单号+行号 缓存订单行
        Map<String, ForecastOrderLineSDO> forecastOrderLineSDOMap = new HashMap<>();
        for (ForecastOrderSDO forecastOrderSDO : forecastOrderSDOS) {
            forecastOrderSDOMap.put(forecastOrderSDO.getOrderBizId(), forecastOrderSDO);
            for (ForecastOrderLineSDO forecastOrderLineSDO : forecastOrderSDO.getForecastOrderLineSDOList()) {
                String key = String.format("%s_%s", forecastOrderSDO.getOrderBizId(), forecastOrderLineSDO.getSerialNumber());
                forecastOrderLineSDOMap.put(key, forecastOrderLineSDO);
            }
        }

        for (ForecastOrderBizModifyActivityRequest modifyActivityRequest : request.getActivityList()) {
            ForecastOrderBizModifyActivityResponse response = ForecastOrderBizModifyActivityResponse.builder()
                    .salesOrderNo(modifyActivityRequest.getSalesOrderNo())
                    .lineNum(modifyActivityRequest.getLineNum())
                    .build();
            responses.add(response);

            ForecastOrderSDO forecastOrderSDO = forecastOrderSDOMap.get(modifyActivityRequest.getSalesOrderNo());
            // 存在性校验
            if (Objects.isNull(forecastOrderSDO)) {
                response.setErrorCode("OC-04-003-01-16-001");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                continue;
            }

            String key = String.format("%s_%s", modifyActivityRequest.getSalesOrderNo(), modifyActivityRequest.getLineNum());
            ForecastOrderLineSDO forecastOrderLineSDO = forecastOrderLineSDOMap.get(key);
            // 存在性校验
            if (Objects.isNull(forecastOrderLineSDO)) {
                response.setErrorCode("OC-04-003-01-16-002");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                continue;
            }

            Map<String, Object> features = forecastOrderLineSDO.getFeatures();
            if (MapUtils.isEmpty(features) || Objects.isNull(features.get(ForecastConstants.ACTIVITY_DETAILS))) {
                // 订单行不带活动信息时报错
                response.setErrorCode("OC-04-003-01-16-012");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                continue;
            }

            try {
                // 活动修改主逻辑
                List<ActivitySDO> activitySDOList = JSONObject.parseArray(JSON.toJSONString(features.get(ForecastConstants.ACTIVITY_DETAILS)), ActivitySDO.class);
                Map<String, ActivitySDO> activityCodeMap = activitySDOList.stream().collect(Collectors.toMap(o -> o.getActivityCode() + "-" + o.getActivityTermid(), Function.identity()));
                activitySDOList.forEach(o -> o.setIsSelect(false));
                List<ForecastOrderBizModifyActivity> activityList = modifyActivityRequest.getDetailActivityList();

                //活动类型选择次数统计
                List<String> activityTypeList = new ArrayList<>();
                Long activityPrice = null;
                if (CollectionUtils.isNotEmpty(activityList)) {
                    for (ForecastOrderBizModifyActivity forecastOrderBizModifyActivity : activityList) {
                        String activityCode = forecastOrderBizModifyActivity.getActivityId();
                        String activityProjectCode = forecastOrderBizModifyActivity.getActivityLineNo();
                        String activityType = forecastOrderBizModifyActivity.getActivityType();

                        if (!activityCodeMap.containsKey(activityCode + "-" + activityProjectCode)) {
                            response.setErrorCode("OC-04-003-01-16-012");
                            response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                            continue;
                        }
                        ActivitySDO activitySDO = activityCodeMap.get(activityCode + "-" + activityProjectCode);
                        if (!activitySDO.getActivityType().equals(activityType)) {
                            response.setErrorCode("OC-04-003-01-16-013");
                            response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                            continue;
                        }

                        if (activityTypeList.contains(activityType)) {
                            response.setErrorCode("OC-04-003-01-16-014");
                            response.setMessage(ErrorMessage.code(response.getErrorCode(), activityType).getDisplayErrorMessage());
                            continue;
                        }
                        if (activityType.equals(ActivityTypeEnum.SPECIAL_OFFER_PRICE.getValue())) {
                            // 特价活动获取特价价格
                            activityPrice = activitySDO.getSpecialOfferPrice();
                        } else if (activityType.equals(ActivityTypeEnum.TAKE_GIFT.getValue())) {
                            //赠品校验
                            List<ForecastOrderBizModifyGiftRequest> chooseModifyGift = forecastOrderBizModifyActivity.getGiftList();
                            if (CollectionUtils.isEmpty(chooseModifyGift)) {
                                response.setErrorCode("OC-04-003-01-16-015");
                                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                                continue;
                            }
                            List<GiftSDO> finalGiftList = new ArrayList<>();

                            List<GiftSDO> giftList = activitySDO.getGiftList();
                            Map<String, List<GiftSDO>> originGiftCodeMap = giftList.stream().collect(Collectors.groupingBy(o -> o.getGiftSalesUnitCode() + "-" + o.getScItemCode() + "-" + o.getGiftDisable()));
                            Map<String, List<GiftSDO>> originGiftDisableFlagMap = giftList.stream().collect(Collectors.groupingBy(o -> o.getGiftSalesUnitCode() + "-" + o.getGiftDisable()));
                            Map<String, List<ForecastOrderBizModifyGiftRequest>> disableChooseGiftMap = chooseModifyGift.stream().collect(Collectors.groupingBy(ForecastOrderBizModifyGiftRequest::getGiftDisable));

                            List<ForecastOrderBizModifyGiftRequest> trueGiftList = disableChooseGiftMap.get("true");
                            List<ForecastOrderBizModifyGiftRequest> falseGiftList = disableChooseGiftMap.get("false");

                            if (CollectionUtils.isNotEmpty(trueGiftList)) {
                                for (ForecastOrderBizModifyGiftRequest modifyGiftRequest : trueGiftList) {
                                    String giftSalesUnitCode = modifyGiftRequest.getGiftSalesUnitCode();
                                    String giftCode = modifyGiftRequest.getGiftCode();
                                    int giftNumber = Integer.parseInt(modifyGiftRequest.getGiftNumber());
                                    boolean chooseDisable = Boolean.parseBoolean(modifyGiftRequest.getGiftDisable());

                                    if (!originGiftCodeMap.containsKey(giftSalesUnitCode + "-" + giftCode + "-" + chooseDisable)) {
                                        response.setErrorCode("OC-04-003-01-16-016");
                                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                                        return Result.fail(responses, "OC-04-003-01-16-020", "活动修改失败");
                                    }

                                    List<GiftSDO> giftSDOS = originGiftCodeMap.get(giftSalesUnitCode + "-" + giftCode + "-" + chooseDisable);

                                    GiftSDO originGiftSDO = giftSDOS.get(0);
                                    Integer originGiftNumber = originGiftSDO.getGiftNumber();
                                    if (originGiftNumber != giftNumber) {
                                        response.setErrorCode("OC-04-003-01-16-017");
                                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                                        return Result.fail(responses, "OC-04-003-01-16-020", "活动修改失败");
                                    }
                                    GiftSDO giftSDO = new GiftSDO();
                                    BeanUtils.copyProperties(originGiftSDO, giftSDO);
                                    giftSDO.setRemark(modifyGiftRequest.getNote());
                                    giftSDO.setGiftNumber(Integer.parseInt(modifyGiftRequest.getGiftNumber()));
                                    finalGiftList.add(giftSDO);
                                }
                            }
                            if (CollectionUtils.isNotEmpty(falseGiftList)) {
                                Map<String, List<ForecastOrderBizModifyGiftRequest>> saleUnitMap = falseGiftList.stream().collect(groupingBy(ForecastOrderBizModifyGiftRequest::getGiftSalesUnitCode));
                                for (Map.Entry<String, List<ForecastOrderBizModifyGiftRequest>> unitEntry : saleUnitMap.entrySet()) {
                                    String unit = unitEntry.getKey();
                                    List<ForecastOrderBizModifyGiftRequest> chooseGiftList = unitEntry.getValue();
                                    int totalNumber = chooseGiftList.stream().mapToInt(o -> Integer.parseInt(o.getGiftNumber())).sum();
                                    List<GiftSDO> unitGiftSDOS = originGiftDisableFlagMap.get(unit + "-" + "false");
                                    Integer originNumber = unitGiftSDOS.get(0).getGiftNumber();

                                    if (totalNumber < originNumber) {
                                        response.setErrorCode("OC-04-003-01-16-018");
                                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                                        return Result.fail(responses, "OC-04-003-01-16-020", "活动修改失败");
                                    } else if (totalNumber > originNumber) {
                                        response.setErrorCode("OC-04-003-01-16-019");
                                        response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                                        return Result.fail(responses, "OC-04-003-01-16-020", "活动修改失败");
                                    }
                                    for (ForecastOrderBizModifyGiftRequest modifyGiftRequest : chooseGiftList) {
                                        String giftCode = modifyGiftRequest.getGiftCode();
                                        if (!originGiftCodeMap.containsKey(unit + "-" + giftCode + "-" + "false")) {
                                            response.setErrorCode("OC-04-003-01-16-016");
                                            response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
                                            return Result.fail(responses, "OC-04-003-01-16-020", "活动修改失败");
                                        }
                                        List<GiftSDO> giftSDOS = originGiftCodeMap.get(unit + "-" + giftCode + "-" + "false");

                                        GiftSDO giftSDO = new GiftSDO();
                                        BeanUtils.copyProperties(giftSDOS.get(0), giftSDO);
                                        giftSDO.setRemark(modifyGiftRequest.getNote());
                                        giftSDO.setGiftNumber(Integer.parseInt(modifyGiftRequest.getGiftNumber()));
                                        finalGiftList.add(giftSDO);
                                    }
                                }
                            }
                            activitySDO.setChooseGiftList(finalGiftList);
                        }
                        activitySDO.setIsSelect(true);
                        activityTypeList.add(activityType);
                        features.put(ForecastConstants.REMOVE_ACTIVITY_ALL_INFO, "false");
                        features.put(ForecastConstants.REMOVE_ACTIVITY_PRICE, "false");
                    }
                }
                String activityNumbers = activitySDOList.stream().filter(ActivitySDO::getIsSelect).map(ActivitySDO::getActivityTermid).collect(joining("/"));
                String activityCodes = activitySDOList.stream().filter(ActivitySDO::getIsSelect).map(ActivitySDO::getActivityCode).collect(joining("/"));
                String activityNames = activitySDOList.stream().filter(ActivitySDO::getIsSelect).map(ActivitySDO::getActivityName).collect(joining("/"));

                features.put(ForecastConstants.ACTIVITY_DETAILS, activitySDOList);
                features.put(ForecastConstants.ACTIVITY_NUMBER, activityNumbers);
                features.put(ForecastConstants.ACTIVITY_TAG, 0);
                forecastOrderLineSDO.setActivityCode(activityCodes);
                forecastOrderLineSDO.setActivityNumber(activityNumbers);
                forecastOrderLineSDO.setActivityName(activityNames);

                forecastOrderLineSDO.setModifierId(modifier.getId());
                forecastOrderLineSDO.setModofierCode(modifierCode);
                forecastOrderLineSDO.setModifierName(modifier.getName());
                forecastOrderLineSDO.setGmtModified(new Date());
                forecastOrderLineSDO.setActivityPrice(activityPrice);
                if (Objects.isNull(activityPrice)) {
                    features.put(ForecastConstants.REMOVE_ACTIVITY_PRICE, "true");
                    forecastOrderLineSDO.setTotalActivityFee(null);
                } else {
                    forecastOrderLineSDO.setTotalActivityFee(new BigDecimal(forecastOrderLineSDO.getActivityPrice()).multiply(new BigDecimal(forecastOrderLineSDO.getQuantity())).longValue());
                }

                Boolean updateResult = forecastOrderLineWriteRepository.update(forecastOrderLineSDO);
                if (Boolean.TRUE.equals(updateResult)) {
                    // 修改成功直接跳过
                    continue;
                }
                response.setErrorCode("OC-04-003-01-16-010");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
            } catch (Exception e) {
                log.error("ForecastOrderBizWriteServiceImpl#batchModifyReply error", e);
                response.setErrorCode("OC-04-003-01-16-010");
                response.setMessage(ErrorMessage.code(response.getErrorCode()).getDisplayErrorMessage());
            }
        }

        return Result.success(responses);
    }

    private List<String> exchangeInnerForecast(List<ConfirmForecastReplyDTO> confirmReplyList, String taskId, List<ConfirmReplyResponseDTO> responseDTOS) {

        ForecastOrderLineBizDO forecastOrderLineBizDO = ConfirmForecastBizDTOTODOConvert.convert(confirmReplyList);
        List<String> innerLineIdList = new ArrayList<>();
        BatchQueryByBizDoListResponse batchQueryByBizDoListResponse = forecastOrderLineQueryRepository.queryByBizList(forecastOrderLineBizDO);

        if (Objects.isNull(batchQueryByBizDoListResponse) || CollectionUtils.isEmpty(batchQueryByBizDoListResponse.getResult())) {
            confirmReplyList.forEach(confirmForecastReplyDTO -> {
                ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                confirmReplyResponseDTO.setErrorCode("OC-04-001-01-16-017");
                confirmReplyResponseDTO.setMessage("预报订单不存在");
                confirmReplyResponseDTO.setBatchTaskId(taskId);
                responseDTOS.add(confirmReplyResponseDTO);
            });
        }
        Map<String, ForecastOrderLineBizResponseDO> existForecastMap = Nullable.stream(batchQueryByBizDoListResponse.getResult()).collect(Collectors.toMap(o -> o.getForecastOrderBizNo() + "-" + o.getLineNo(), Function.identity()));

        for (ConfirmForecastReplyDTO confirmForecastReplyDTO : confirmReplyList) {
            String key = confirmForecastReplyDTO.getSalesOrderNo() + "-" + confirmForecastReplyDTO.getLineNum();
            if (!existForecastMap.containsKey(key)) {
                ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                confirmReplyResponseDTO.setErrorCode("OC-04-001-01-16-017");
                confirmReplyResponseDTO.setMessage("预报订单不存在");
                confirmReplyResponseDTO.setBatchTaskId(taskId);
                responseDTOS.add(confirmReplyResponseDTO);
                continue;
            }
            innerLineIdList.add(String.valueOf(existForecastMap.get(key).getLineId()));
        }
        return innerLineIdList;
    }


    private List<String> exchangeBizForecast(ConfirmReplyRequest request, String taskId, List<ConfirmReplyResponseDTO> responseDTOS) {
        List<ConfirmForecastReplyDTO> confirmReplyList = request.getConfirmReplyList();
        List<String> salesOrderNoList = confirmReplyList.stream().map(confirmReply -> confirmReply.getSalesOrderNo()).distinct().collect(Collectors.toList());
        List<String> innerLineIdList = new ArrayList<>();
        List<ConfirmForecastReplyDTO> confirmForecastList = new ArrayList<>();
        // 校验预报订单是否存在
        BatchQueryForecastByBizNoRequest batchQueryForecastByBizNoRequest = new BatchQueryForecastByBizNoRequest();
        batchQueryForecastByBizNoRequest.setBizNoList(salesOrderNoList);
        batchQueryForecastByBizNoRequest.setFromSys(request.getFromSys());
        batchQueryForecastByBizNoRequest.setBusinessType(request.getBusinessType());
        batchQueryForecastByBizNoRequest.setBusinessUnitCode(request.getBusinessUnitCode());
        List<ForecastOrderSDO> forecastOrderSDOS = forecastOrderQueryRepository.queryByOrderBizNoWithBizCode(batchQueryForecastByBizNoRequest);
        if(CollectionUtils.isEmpty(forecastOrderSDOS)){
            confirmReplyList.forEach(confirmForecastReplyDTO -> {
                ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                confirmReplyResponseDTO.setErrorCode("OC-04-001-01-16-017");
                confirmReplyResponseDTO.setMessage("预报订单不存在");
                confirmReplyResponseDTO.setBatchTaskId(taskId);
                responseDTOS.add(confirmReplyResponseDTO);
            });
        }else {
            Map<String, ForecastOrderSDO> forecastOrderSDOMap = Nullable.stream(forecastOrderSDOS)
                    .collect(toMap(o -> o.getOrderBizId() + "-" + o.getFromSys() + "-" + o.getBusinessType() + "-" + o.getBusinessUnitCode(), Function.identity()));
            for (ConfirmForecastReplyDTO confirmForecastReplyDTO : confirmReplyList) {
                String key = confirmForecastReplyDTO.getSalesOrderNo() + "-" + request.getFromSys() + "-" + request.getBusinessType() + "-" + request.getBusinessUnitCode();
                if (!forecastOrderSDOMap.containsKey(key)) {
                    ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                    confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                    confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                    confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                    confirmReplyResponseDTO.setErrorCode("OC-04-001-01-16-017");
                    confirmReplyResponseDTO.setMessage("预报订单不存在");
                    confirmReplyResponseDTO.setBatchTaskId(taskId);
                    responseDTOS.add(confirmReplyResponseDTO);
                } else {
                    confirmForecastList.add(confirmForecastReplyDTO);
                }
            }
        }
        // 校验预报订单行是否存在
        if(CollectionUtils.isNotEmpty(confirmForecastList)) {
            //生成key是主单号，value是行号集合的map
            Map<String, List<String>> salesOrderNoMap = confirmForecastList.stream().collect(toMap(ConfirmForecastReplyDTO::getSalesOrderNo, a -> {
                List<String> salesOrderNoLineNolist = new ArrayList<>();
                salesOrderNoLineNolist.add(a.getSalesOrderNo() + "-" + a.getLineNum());
                return salesOrderNoLineNolist;
            }, (l1, l2) -> {
                l1.addAll(l2);
                return l1;
            }));
            log.info("salesOrderNoMap参数:{}", JSON.toJSONString(salesOrderNoMap));
            ForecastOrderLineBizDO forecastOrderLineBizDO = ConfirmForecastBizDTOTODOConvert.convert(confirmForecastList);
            BatchQueryByBizDoListResponse batchQueryByBizDoListResponse = forecastOrderLineQueryRepository.queryByBizList(forecastOrderLineBizDO);
            if (Objects.isNull(batchQueryByBizDoListResponse) || CollectionUtils.isEmpty(batchQueryByBizDoListResponse.getResult())) {
                confirmReplyList.forEach(confirmForecastReplyDTO -> {
                    ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                    confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                    confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                    confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                    confirmReplyResponseDTO.setErrorCode("OC-04-005-01-16-004");
                    confirmReplyResponseDTO.setMessage("预报订单行号不存在");
                    confirmReplyResponseDTO.setBatchTaskId(taskId);
                    responseDTOS.add(confirmReplyResponseDTO);
                });
            }else {
                Map<String, Map<String, ForecastOrderLineBizResponseDO>> existForecastMap = Nullable.stream(batchQueryByBizDoListResponse.getResult())
                        .collect(toMap(ForecastOrderLineBizResponseDO::getForecastOrderBizNo, o -> {
                            Map<String, ForecastOrderLineBizResponseDO> map = new HashMap<>();
                            map.put(o.getForecastOrderBizNo() + "-" + o.getLineNo(), o);
                            return map;
                        }, (m1, m2) -> {
                            m1.putAll(m2);
                            return m1;
                        }));

                A:
                for (Map.Entry<String, List<String>> orderNoEntry : salesOrderNoMap.entrySet()) {
                    Map<String, ForecastOrderLineBizResponseDO> keyExistForecastMap = existForecastMap.get(orderNoEntry.getKey());
                    log.info("keyExistForecastMap结果:{}",JSON.toJSONString(keyExistForecastMap));
                    for (String orderNoLineNo : orderNoEntry.getValue()) {
                        if (!keyExistForecastMap.containsKey(orderNoLineNo)){
                            ConfirmReplyResponseDTO confirmReplyResponseDTO = getConfirmReplyResponseDTO(orderNoLineNo, taskId);
                            responseDTOS.add(confirmReplyResponseDTO);
                            //最外层循环continue
                            continue A;
                        }
                    }
                    List<ForecastOrderLineBizResponseDO> forecastOrderLineBizResponseDOList = keyExistForecastMap.values().stream().filter(orderLine -> orderNoEntry.getValue().contains(orderLine.getForecastOrderBizNo() + "-" + orderLine.getLineNo())).collect(Collectors.toList());
                    log.info("forecastOrderLineBizResponseDOList结果:{}",JSON.toJSONString(forecastOrderLineBizResponseDOList));
                    forecastOrderLineBizResponseDOList.forEach(a -> innerLineIdList.add(String.valueOf(a.getLineId())));
                }
            }
        }
        log.info("innerLineIdList结果:{}",JSON.toJSONString(innerLineIdList));
        return innerLineIdList;
    }

    private List<String> exchangeGroupForecast(ConfirmGroupReplyRequest request, List<ConfirmReplyResponseDTO> responseDTOS){

        List<ConfirmForecastReplyDTO> confirmReplyList = request.getConfirmReplyList();
        List<String> salesOrderNoList = confirmReplyList.stream().map(confirmReply -> confirmReply.getSalesOrderNo()).distinct().collect(Collectors.toList());
        List<String> innerLineIdList = new ArrayList<>();
        List<ConfirmForecastReplyDTO> confirmForecastList = new ArrayList<>();
        // 校验预报订单是否存在
        BatchQueryForecastByBizNoRequest batchQueryForecastByBizNoRequest = new BatchQueryForecastByBizNoRequest();
        batchQueryForecastByBizNoRequest.setBizNoList(salesOrderNoList);
        batchQueryForecastByBizNoRequest.setFromSys(request.getFromSys());
        batchQueryForecastByBizNoRequest.setBusinessType(request.getBusinessType());
        batchQueryForecastByBizNoRequest.setBusinessUnitCode(request.getBusinessUnitCode());
        List<ForecastOrderSDO> forecastOrderSDOS = forecastOrderQueryRepository.queryByOrderBizNoWithBizCode(batchQueryForecastByBizNoRequest);
        if(CollectionUtils.isEmpty(forecastOrderSDOS)){
            confirmReplyList.forEach(confirmForecastReplyDTO -> {
                ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                confirmReplyResponseDTO.setErrorCode("OC-04-001-01-16-017");
                confirmReplyResponseDTO.setMessage("预报订单不存在");
                responseDTOS.add(confirmReplyResponseDTO);
            });
        }else {
            Map<String, ForecastOrderSDO> forecastOrderSDOMap = Nullable.stream(forecastOrderSDOS)
                    .collect(toMap(o -> o.getOrderBizId() + "-" + o.getFromSys() + "-" + o.getBusinessType() + "-" + o.getBusinessUnitCode(), Function.identity()));
            for (ConfirmForecastReplyDTO confirmForecastReplyDTO : confirmReplyList) {
                String key = confirmForecastReplyDTO.getSalesOrderNo() + "-" + request.getFromSys() + "-" + request.getBusinessType() + "-" + request.getBusinessUnitCode();
                if (!forecastOrderSDOMap.containsKey(key)) {
                    ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                    confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                    confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                    confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                    confirmReplyResponseDTO.setErrorCode("OC-04-001-01-16-017");
                    confirmReplyResponseDTO.setMessage("预报订单不存在");
                    responseDTOS.add(confirmReplyResponseDTO);
                } else {
                    confirmForecastList.add(confirmForecastReplyDTO);
                }
            }
        }
        // 校验预报订单行是否存在
        if(CollectionUtils.isNotEmpty(confirmForecastList)) {
            //生成key是主单号，value是行号集合的map
            Map<String, List<String>> salesOrderNoMap = confirmForecastList.stream().collect(toMap(ConfirmForecastReplyDTO::getSalesOrderNo, a -> {
                List<String> salesOrderNoLineNolist = new ArrayList<>();
                salesOrderNoLineNolist.add(a.getSalesOrderNo() + "-" + a.getLineNum());
                return salesOrderNoLineNolist;
            }, (l1, l2) -> {
                l1.addAll(l2);
                return l1;
            }));
            ForecastOrderLineBizDO forecastOrderLineBizDO = ConfirmForecastBizDTOTODOConvert.convert(confirmForecastList);
            BatchQueryByBizDoListResponse batchQueryByBizDoListResponse = forecastOrderLineQueryRepository.queryByBizList(forecastOrderLineBizDO);
            if (Objects.isNull(batchQueryByBizDoListResponse) || CollectionUtils.isEmpty(batchQueryByBizDoListResponse.getResult())) {
                confirmReplyList.forEach(confirmForecastReplyDTO -> {
                    ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
                    confirmReplyResponseDTO.setSalesOrderNo(confirmForecastReplyDTO.getSalesOrderNo());
                    confirmReplyResponseDTO.setLineNo(confirmForecastReplyDTO.getLineNum());
                    confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
                    confirmReplyResponseDTO.setErrorCode("OC-04-005-01-16-004");
                    confirmReplyResponseDTO.setMessage("预报订单行号不存在");
                    responseDTOS.add(confirmReplyResponseDTO);
                });
            }else {
                Map<String, Map<String, ForecastOrderLineBizResponseDO>> existForecastMap = Nullable.stream(batchQueryByBizDoListResponse.getResult())
                        .collect(toMap(ForecastOrderLineBizResponseDO::getForecastOrderBizNo, o -> {
                            Map<String, ForecastOrderLineBizResponseDO> map = new HashMap<>();
                            map.put(o.getForecastOrderBizNo() + "-" + o.getLineNo(), o);
                            return map;
                        }, (m1, m2) -> {
                            m1.putAll(m2);
                            return m1;
                        }));

                A:
                for (Map.Entry<String, List<String>> orderNoEntry : salesOrderNoMap.entrySet()) {
                    Map<String, ForecastOrderLineBizResponseDO> keyExistForecastMap = existForecastMap.get(orderNoEntry.getKey());
                    for (String orderNoLineNo : orderNoEntry.getValue()) {
                        if (!keyExistForecastMap.containsKey(orderNoLineNo)){
                            ConfirmReplyResponseDTO confirmReplyResponseDTO = getConfirmReplyResponseDTO(orderNoLineNo, null);
                            responseDTOS.add(confirmReplyResponseDTO);
                            //最外层循环continue
                            continue A;
                        }
                    }
                    keyExistForecastMap.values().forEach(a->innerLineIdList.add(String.valueOf(a.getLineId())));
                }
            }
        }
        return innerLineIdList;
    }

    @NotNull
    private static ConfirmReplyResponseDTO getConfirmReplyResponseDTO(String orderNoLineNo, String taskId) {
        String[] orderNoAndLineNo = orderNoLineNo.split("-");
        ConfirmReplyResponseDTO confirmReplyResponseDTO = new ConfirmReplyResponseDTO();
        confirmReplyResponseDTO.setSalesOrderNo(orderNoAndLineNo[0]);
        confirmReplyResponseDTO.setLineNo(orderNoAndLineNo[1]);
        confirmReplyResponseDTO.setSuccess(Boolean.FALSE);
        confirmReplyResponseDTO.setErrorCode("OC-04-005-01-16-004");
        confirmReplyResponseDTO.setMessage("预报订单行号不存在");
        confirmReplyResponseDTO.setBatchTaskId(taskId);
        return confirmReplyResponseDTO;
    }

    /**
     * 更新订单行状态
     */
    @EpochTransactional(appCode = "mn_order_center", dataSourceCode = "cr_ots", dataSourceType = "app")
    private void updateOrderLineStatus(List<ForecastOrderLineSDO> orderLineList) {
        if (CollectionUtils.isEmpty(orderLineList)) {
            return;
        }
        log.info("ForecastOrderBizWriteServiceImpl#updateOrderLineStatus request:{}", JSON.toJSONString(orderLineList));

        Map<String, List<Long>> completedListMap = new HashMap<>();
        Map<String, List<Long>> canceledListMap = new HashMap<>();
        orderLineList.forEach(orderLine -> {
            // 根据关闭原因&推进状态分组进行关闭
            if (ForecastStatusEnum.PARTIAL_REPLY.getNumValue().equals(orderLine.getStatus())) {
                List<Long> completedList;
                if (completedListMap.containsKey(orderLine.getRefuseReasonCode())) {
                    completedList = completedListMap.get(orderLine.getRefuseReasonCode());
                } else {
                    completedList = new ArrayList<>();
                }
                completedList.add(orderLine.getId());
                completedListMap.put(orderLine.getRefuseReasonCode(), completedList);

                // 部分交货状态的订单行，推进到已完成状态（这里修改子单状态是为了后面推进主单状态，勿删）
                orderLine.setStatus(ForecastStatusEnum.COMPLETED.getNumValue());
            } else {
                List<Long> canceledList;
                if (canceledListMap.containsKey(orderLine.getRefuseReasonCode())) {
                    canceledList = canceledListMap.get(orderLine.getRefuseReasonCode());
                } else {
                    canceledList = new ArrayList<>();
                }
                canceledList.add(orderLine.getId());
                canceledListMap.put(orderLine.getRefuseReasonCode(), canceledList);

                // 其他状态的订单行，推进到已取消状态（这里修改子单状态是为了后面推进主单状态，勿删）
                orderLine.setStatus(ForecastStatusEnum.CANCELLED.getNumValue());
            }
        });
        log.info("ForecastOrderBizWriteServiceImpl#updateOrderLineStatus completedListMap={} canceledListMap={}",
                JSON.toJSONString(completedListMap), JSON.toJSONString(canceledListMap));

        batchUpdateForClose(completedListMap, GeneralStatusEnum.YES.getCode(), ForecastStatusEnum.COMPLETED.getNumValue());
        batchUpdateForClose(canceledListMap, GeneralStatusEnum.YES.getCode(), ForecastStatusEnum.CANCELLED.getNumValue());
    }

    /**
     * 更新订单状态
     */
    @EpochTransactional(appCode = "mn_order_center", dataSourceCode = "cr_ots", dataSourceType = "app")
    private void updateOrderStatus(List<ForecastOrderSDO> orderList) {
        if (CollectionUtils.isEmpty(orderList)) {
            return;
        }
        log.info("ForecastOrderBizWriteServiceImpl#updateOrderStatus request:{}", JSON.toJSONString(orderList));
        CountDownLatch countDownLatch = new CountDownLatch(orderList.size());
        orderList.forEach(order -> ThreadPoolUtil.execute(() -> {
            log.info("ForecastOrderBizWriteServiceImpl#updateOrderStatus order={}", JSON.toJSONString(order));
            List<Integer> priorityStatus = Lists.newArrayList(
                    ForecastStatusEnum.DRAFT.getNumValue(),
                    ForecastStatusEnum.WAITING_FOR_REPLY.getNumValue(),
                    ForecastStatusEnum.PARTIAL_REPLY.getNumValue(),
                    ForecastStatusEnum.NOTACTIVE.getNumValue()
            );

            List<Integer> allStatus = order.getForecastOrderLineSDOList().stream()
                    .map(ForecastOrderLineSDO::getStatus)
                    .distinct().collect(Collectors.toList());
            log.info("ForecastOrderBizWriteServiceImpl#updateOrderStatus allStatus={}", allStatus);

            Integer originStatus = order.getStatus();
            // 2. 子单只存在已取消的状态，主单就为已取消
            order.setStatus(ForecastStatusEnum.CANCELLED.getNumValue());
            allStatus.forEach(orderLineStatus -> {
                // 1. 只要子单包含待提交、待回复、部分回复、未生效的状态之一，主单就为该状态x
                if (priorityStatus.contains(orderLineStatus) && orderLineStatus >= originStatus) {
                    log.info("ForecastOrderBizWriteServiceImpl#updateOrderStatus setStatus({})", orderLineStatus);
                    order.setStatus(orderLineStatus);
                    return;
                }
            });

            // 一盘货批量关闭 推进主单状态为已完成（子单状态全部为已完成，或 子单状态只为 已完成 和 已取消）
            Set<Integer> lineStatusSet = new HashSet<>(allStatus);
            if (lineStatusSet.size() <= 2) {
                lineStatusSet.remove(ForecastStatusEnum.CANCELLED.getNumValue());
                if (lineStatusSet.isEmpty()) {
                    order.setStatus(ForecastStatusEnum.CANCELLED.getNumValue());
                } else {
                    lineStatusSet.remove(ForecastStatusEnum.COMPLETED.getNumValue());
                    if (lineStatusSet.isEmpty()) {
                        order.setStatus(ForecastStatusEnum.COMPLETED.getNumValue());
                    }
                }
            }
            order.setGmtModified(new Date());

            try {
                forecastOrderWriteRepository.modifyForecast(order);
            } catch (Exception e) {
                log.error("ForecastOrderBizWriteServiceImpl#updateOrderStatus modifyForecast error", e);
            } finally {
                countDownLatch.countDown();
            }
        }));

        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("ForecastOrderBizWriteServiceImpl#updateOrderStatus await error", e);
        }
    }
}
